package com.appbee.core.client.data;

import java.util.List;
import java.util.Set;

import com.google.gwt.view.client.Range;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.ServerFailure;
import com.google.web.bindery.requestfactory.shared.Violation;

/**
 * A fetch buffer for single Range in BufferedDataProvider
 * 
 * @author jakobmarrunarsson
 * 
 * @param <T>
 */
public class Fetch<T> extends Receiver<List<T>>
{
	private final Range range;
	private final int filterHashCode;
	private final IDataUpdater<T> updater;
	private final IFetcher<T> fetcher;
	private final ISortInfo sortInfo;
	private List<T> data;
	private boolean exact = false;
	private int count = 0;
	private Range fetchingRange;
	private boolean fetching = false;

	public Fetch(Range range, int filterHashCode, IDataUpdater<T> updater,
			IFetcher<T> fetcher, ISortInfo sortInfo)
	{
		super();
		this.range = range;
		this.filterHashCode = filterHashCode;
		this.updater = updater;
		this.fetcher = fetcher;
		this.sortInfo = sortInfo;
	}

	public Range getRange()
	{
		return range;
	}

	public List<T> getData()
	{
		return data;
	}

	public boolean isFetching()
	{
		return fetching;
	}

	public boolean isExact()
	{
		return exact;
	}

	public void doFetch(Range viewRange)
	{
		if (fetching)
			return;
		else if (data != null)
		{
			updater.updateRowData(range.getStart(), data);
			updater.updateRowCount(count, exact);
		}
		else
		{
			fetching = true;
			fetchingRange = viewRange;
			fetcher.fetch(viewRange, sortInfo, this);
		}

	}

	@Override
	public void onSuccess(List<T> response)
	{
		boolean hasResponse = data != null;
		data = response;
		if (!hasResponse)
		{
			updater.updateRowData(fetchingRange.getStart(), response);
			exact = response.size() < fetchingRange.getLength();
			if (exact)// There no more data
			{
				count = response.size() + fetchingRange.getStart();
				updater.updateRowCount(count, true);
			}
			else
			// Fetch the rest of data
			{
				fetchingRange = range;
				fetcher.fetch(range, sortInfo, this);
			}
		}
		else
		{
			count = response.size() + range.getStart();
			exact = response.size() < range.getLength();
			updater.updateRowCount(count, exact);
			updater.updateRowData(fetchingRange.getStart(), response);
			fetchingRange = null;
		}
		fetching = false;
	}

	@Override
	public void onFailure(ServerFailure error)
	{
		fetching = false;
		super.onFailure(error);
	}

	@Override
	public void onViolation(Set<Violation> errors)
	{
		fetching = false;
		super.onViolation(errors);
	}

	public int getFilterHashCode()
	{
		return filterHashCode;
	}

}
